<?php
// /////////////////////////////////////////////////////////////////////////////////////////////////
// GIF Util - (C) 2003 Yamasoft (S/C)
// http://www.yamasoft.com
// All Rights Reserved
// This file can be frelly copied, distributed, modified, updated by anyone under the only
// condition to leave the original address (Yamasoft, http://www.yamasoft.com) and this header.
// /////////////////////////////////////////////////////////////////////////////////////////////////
// <gif>  = gif_loadFile(filename, [index])
// <bool> = gif_getSize(<gif> or filename, &width, &height)
// <bool> = gif_outputAsPng(<gif>, filename, [bgColor])
// <bool> = gif_outputAsBmp(<gif>, filename, [bgcolor])
// <bool> = gif_outputAsJpeg(<gif>, filename, [bgcolor]) - Requires cjpeg
// /////////////////////////////////////////////////////////////////////////////////////////////////
// /////////////////////////////////////////////////////////////////////////////////////////////////
function gif_loadFile( $lpszFileName, $iIndex = 0 )
{
	$gif = new CGIF();

	if ( !$gif->loadFile( $lpszFileName, $iIndex ) ) {
		return false;
	}

	return $gif;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
function gif_outputAsBmp( $gif, $lpszFileName, $bgColor = -1 )
{
	if ( !isSet( $gif ) || ( @get_class( $gif ) <> "cgif" ) || !$gif->loaded() || ( $lpszFileName == "" ) ) {
		return false;
	}

	$fd = $gif->getBmp( $bgColor );
	if ( strlen( $fd ) <= 0 ) {
		return false;
	}

	if ( !( $fh = @fOpen( $lpszFileName, "wb" ) ) ) {
		return false;
	}
	@fWrite( $fh, $fd, strlen( $fd ) );
	@fFlush( $fh );
	@fClose( $fh );
	return true;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
function gif_outputAsPng( $gif, $lpszFileName, $bgColor = -1 )
{
	if ( !isSet( $gif ) || ( @get_class( $gif ) <> "cgif" ) || !$gif->loaded() || ( $lpszFileName == "" ) ) {
		return false;
	}

	$fd = $gif->getPng( $bgColor );
	if ( strlen( $fd ) <= 0 ) {
		return false;
	}

	if ( !( $fh = @fopen( $lpszFileName, "wb" ) ) ) {
		return false;
	}
	@fWrite( $fh, $fd, strlen( $fd ) );
	@fFlush( $fh );
	@fClose( $fh );
	return true;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
function gif_outputAsJpeg( $gif, $lpszFileName, $bgColor = -1 )
{
	if ( gif_outputAsBmp( $gif, "$lpszFileName.bmp", $gbColor ) ) {
		exec( "cjpeg $lpszFileName.bmp >$lpszFileName 2>/dev/null" );
		@unlink( "$lpszFileName.bmp" );

		if ( @file_exists( $lpszFileName ) ) {
			if ( @filesize( $lpszFileName ) > 0 ) {
				return true;
			}

			@unlink( $lpszFileName );
		}
	}

	return false;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
function gif_getSize( $gif, &$width, &$height )
{
	if ( isset( $gif ) && ( @get_class( $gif ) == "cgif" ) && $gif->loaded() ) {
		$width = $gif->width();
		$height = $gif->height();
	} else if ( @file_exists( $gif ) ) {
		$myGIF = new CGIF();
		if ( !$myGIF->getSize( $gif, $width, $height ) ) {
			return false;
		}
	} else {
		return false;
	}

	return true;
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFLZW {
	var $MAX_LZW_BITS;
	var $Fresh, $CodeSize, $SetCodeSize, $MaxCode, $MaxCodeSize, $FirstCode, $OldCode;
	var $ClearCode, $EndCode, $Next, $Vals, $Stack, $sp, $Buf, $CurBit, $LastBit, $Done, $LastByte;
	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	function CGIFLZW()
	{
		$this->MAX_LZW_BITS = 12;
		unset( $this->Next );
		unset( $this->Vals );
		unset( $this->Stack );
		unset( $this->Buf );

		$this->Next = range( 0, ( 1 << $this->MAX_LZW_BITS ) - 1 );
		$this->Vals = range( 0, ( 1 << $this->MAX_LZW_BITS ) - 1 );
		$this->Stack = range( 0, ( 1 << ( $this->MAX_LZW_BITS + 1 ) ) - 1 );
		$this->Buf = range( 0, 279 );
	}
	// /////////////////////////////////////////////////////////////////////////
	function deCompress( $data, &$datLen )
	{
		$stLen = strlen( $data );
		$datLen = 0;
		$ret = "";
		// INITIALIZATION
		$this->LZWCommand( $data, true );

		while ( ( $iIndex = $this->LZWCommand( $data, false ) ) >= 0 ) {
			$ret .= chr( $iIndex );
		}

		$datLen = $stLen - strlen( $data );

		if ( $iIndex != -2 ) {
			return false;
		}

		return $ret;
	}
	// /////////////////////////////////////////////////////////////////////////
	function LZWCommand( &$data, $bInit )
	{
		if ( $bInit ) {
			$this->SetCodeSize = ord( $data{0} );
			$data = substr( $data, 1 );

			$this->CodeSize = $this->SetCodeSize + 1;
			$this->ClearCode = 1 << $this->SetCodeSize;
			$this->EndCode = $this->ClearCode + 1;
			$this->MaxCode = $this->ClearCode + 2;
			$this->MaxCodeSize = $this->ClearCode << 1;

			$this->GetCode( $data, $bInit );

			$this->Fresh = 1;
			for( $i = 0; $i < $this->ClearCode; $i++ ) {
				$this->Next[$i] = 0;
				$this->Vals[$i] = $i;
			}

			for( ; $i < ( 1 << $this->MAX_LZW_BITS ); $i++ ) {
				$this->Next[$i] = 0;
				$this->Vals[$i] = 0;
			}

			$this->sp = 0;
			return 1;
		}

		if ( $this->Fresh ) {
			$this->Fresh = 0;
			do {
				$this->FirstCode = $this->GetCode( $data, $bInit );
				$this->OldCode = $this->FirstCode;
			} while ( $this->FirstCode == $this->ClearCode );

			return $this->FirstCode;
		}

		if ( $this->sp > 0 ) {
			$this->sp--;
			return $this->Stack[$this->sp];
		} while ( ( $Code = $this->GetCode( $data, $bInit ) ) >= 0 ) {
			if ( $Code == $this->ClearCode ) {
				for( $i = 0; $i < $this->ClearCode; $i++ ) {
					$this->Next[$i] = 0;
					$this->Vals[$i] = $i;
				}

				for( ; $i < ( 1 << $this->MAX_LZW_BITS ); $i++ ) {
					$this->Next[$i] = 0;
					$this->Vals[$i] = 0;
				}

				$this->CodeSize = $this->SetCodeSize + 1;
				$this->MaxCodeSize = $this->ClearCode << 1;
				$this->MaxCode = $this->ClearCode + 2;
				$this->sp = 0;
				$this->FirstCode = $this->GetCode( $data, $bInit );
				$this->OldCode = $this->FirstCode;

				return $this->FirstCode;
			}

			if ( $Code == $this->EndCode ) {
				return -2;
			}

			$InCode = $Code;
			if ( $Code >= $this->MaxCode ) {
				$this->Stack[$this->sp] = $this->FirstCode;
				$this->sp++;
				$Code = $this->OldCode;
			} while ( $Code >= $this->ClearCode ) {
				$this->Stack[$this->sp] = $this->Vals[$Code];
				$this->sp++;

				if ( $Code == $this->Next[$Code] ) // Circular table entry, big GIF Error!
					return -1;

				$Code = $this->Next[$Code];
			}

			$this->FirstCode = $this->Vals[$Code];
			$this->Stack[$this->sp] = $this->FirstCode;
			$this->sp++;

			if ( ( $Code = $this->MaxCode ) < ( 1 << $this->MAX_LZW_BITS ) ) {
				$this->Next[$Code] = $this->OldCode;
				$this->Vals[$Code] = $this->FirstCode;
				$this->MaxCode++;

				if ( ( $this->MaxCode >= $this->MaxCodeSize ) && ( $this->MaxCodeSize < ( 1 << $this->MAX_LZW_BITS ) ) ) {
					$this->MaxCodeSize *= 2;
					$this->CodeSize++;
				}
			}

			$this->OldCode = $InCode;
			if ( $this->sp > 0 ) {
				$this->sp--;
				return $this->Stack[$this->sp];
			}
		}

		return $Code;
	}
	// /////////////////////////////////////////////////////////////////////////
	function GetCode( &$data, $bInit )
	{
		if ( $bInit ) {
			$this->CurBit = 0;
			$this->LastBit = 0;
			$this->Done = 0;
			$this->LastByte = 2;
			return 1;
		}

		if ( ( $this->CurBit + $this->CodeSize ) >= $this->LastBit ) {
			if ( $this->Done ) {
				if ( $this->CurBit >= $this->LastBit ) {
					// Ran off the end of my bits
					return 0;
				}
				return -1;
			}

			$this->Buf[0] = $this->Buf[$this->LastByte - 2];
			$this->Buf[1] = $this->Buf[$this->LastByte - 1];

			$Count = ord( $data{0} );
			$data = substr( $data, 1 );

			if ( $Count ) {
				for( $i = 0; $i < $Count; $i++ ) {
					$this->Buf[2 + $i] = ord( $data{$i} );
				}
				$data = substr( $data, $Count );
			} else {
				$this->Done = 1;
			}

			$this->LastByte = 2 + $Count;
			$this->CurBit = ( $this->CurBit - $this->LastBit ) + 16;
			$this->LastBit = ( 2 + $Count ) << 3;
		}

		$iRet = 0;
		for( $i = $this->CurBit, $j = 0; $j < $this->CodeSize; $i++, $j++ ) {
			$iRet |= ( ( $this->Buf[intval( $i / 8 )] &( 1 << ( $i % 8 ) ) ) != 0 ) << $j;
		}

		$this->CurBit += $this->CodeSize;
		return $iRet;
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFCOLORTABLE {
	var $m_nColors;
	var $m_arColors;
	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	function CGIFCOLORTABLE()
	{
		unset( $this->m_nColors );
		unset( $this->m_arColors );
	}
	// /////////////////////////////////////////////////////////////////////////
	function load( $lpData, $num )
	{
		$this->m_nColors = 0;
		$this->m_arColors = array();

		for( $i = 0; $i < $num; $i++ ) {
			$rgb = substr( $lpData, $i * 3, 3 );
			if ( strlen( $rgb ) < 3 ) {
				return false;
			}

			$this->m_arColors[] = ( ord( $rgb{2} ) << 16 ) + ( ord( $rgb{1} ) << 8 ) + ord( $rgb{0} );
			$this->m_nColors++;
		}

		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function toString()
	{
		$ret = "";

		for( $i = 0; $i < $this->m_nColors; $i++ ) {
			$ret .=
			chr( ( $this->m_arColors[$i] &0x000000FF ) ) . // R
			chr( ( $this->m_arColors[$i] &0x0000FF00 ) >> 8 ) . // G
			chr( ( $this->m_arColors[$i] &0x00FF0000 ) >> 16 ); // B
		}

		return $ret;
	}
	// /////////////////////////////////////////////////////////////////////////
	function toRGBQuad()
	{
		$ret = "";

		for( $i = 0; $i < $this->m_nColors; $i++ ) {
			$ret .=
			chr( ( $this->m_arColors[$i] &0x00FF0000 ) >> 16 ) . // B
			chr( ( $this->m_arColors[$i] &0x0000FF00 ) >> 8 ) . // G
			chr( ( $this->m_arColors[$i] &0x000000FF ) ) . // R
			"\x00";
		}

		return $ret;
	}
	// /////////////////////////////////////////////////////////////////////////
	function colorIndex( $rgb )
	{
		$rgb = intval( $rgb ) &0xFFFFFF;
		$r1 = ( $rgb &0x0000FF );
		$g1 = ( $rgb &0x00FF00 ) >> 8;
		$b1 = ( $rgb &0xFF0000 ) >> 16;
		$idx = -1;

		for( $i = 0; $i < $this->m_nColors; $i++ ) {
			$r2 = ( $this->m_arColors[$i] &0x000000FF );
			$g2 = ( $this->m_arColors[$i] &0x0000FF00 ) >> 8;
			$b2 = ( $this->m_arColors[$i] &0x00FF0000 ) >> 16;
			$d = abs( $r2 - $r1 ) + abs( $g2 - $g1 ) + abs( $b2 - $b1 );

			if ( ( $idx == -1 ) || ( $d < $dif ) ) {
				$idx = $i;
				$dif = $d;
			}
		}

		return $idx;
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFFILEHEADER {
	var $m_lpVer;
	var $m_nWidth;
	var $m_nHeight;
	var $m_bGlobalClr;
	var $m_nColorRes;
	var $m_bSorted;
	var $m_nTableSize;
	var $m_nBgColor;
	var $m_nPixelRatio;
	var $m_colorTable;
	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	function CGIFFILEHEADER()
	{
		unset( $this->m_lpVer );
		unset( $this->m_nWidth );
		unset( $this->m_nHeight );
		unset( $this->m_bGlobalClr );
		unset( $this->m_nColorRes );
		unset( $this->m_bSorted );
		unset( $this->m_nTableSize );
		unset( $this->m_nBgColor );
		unset( $this->m_nPixelRatio );
		unset( $this->m_colorTable );
	}
	// /////////////////////////////////////////////////////////////////////////
	function load( $lpData, &$hdrLen )
	{
		$hdrLen = 0;

		$this->m_lpVer = substr( $lpData, 0, 6 );
		if ( ( $this->m_lpVer <> "GIF87a" ) && ( $this->m_lpVer <> "GIF89a" ) ) {
			return false;
		}

		$this->m_nWidth = $this->w2i( substr( $lpData, 6, 2 ) );
		$this->m_nHeight = $this->w2i( substr( $lpData, 8, 2 ) );
		if ( !$this->m_nWidth || !$this->m_nHeight ) {
			return false;
		}

		$b = ord( substr( $lpData, 10, 1 ) );
		$this->m_bGlobalClr = ( $b &0x80 ) ? true : false;
		$this->m_nColorRes = ( $b &0x70 ) >> 4;
		$this->m_bSorted = ( $b &0x08 ) ? true : false;
		$this->m_nTableSize = 2 << ( $b &0x07 );
		$this->m_nBgColor = ord( substr( $lpData, 11, 1 ) );
		$this->m_nPixelRatio = ord( substr( $lpData, 12, 1 ) );
		$hdrLen = 13;

		if ( $this->m_bGlobalClr ) {
			$this->m_colorTable = new CGIFCOLORTABLE();
			if ( !$this->m_colorTable->load( substr( $lpData, $hdrLen ), $this->m_nTableSize ) ) {
				return false;
			}
			$hdrLen += 3 * $this->m_nTableSize;
		}

		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function w2i( $str )
	{
		return ord( substr( $str, 0, 1 ) ) + ( ord( substr( $str, 1, 1 ) ) << 8 );
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFIMAGEHEADER {
	var $m_nLeft;
	var $m_nTop;
	var $m_nWidth;
	var $m_nHeight;
	var $m_bLocalClr;
	var $m_bInterlace;
	var $m_bSorted;
	var $m_nTableSize;
	var $m_colorTable;
	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	function CGIFIMAGEHEADER()
	{
		unset( $this->m_nLeft );
		unset( $this->m_nTop );
		unset( $this->m_nWidth );
		unset( $this->m_nHeight );
		unset( $this->m_bLocalClr );
		unset( $this->m_bInterlace );
		unset( $this->m_bSorted );
		unset( $this->m_nTableSize );
		unset( $this->m_colorTable );
	}
	// /////////////////////////////////////////////////////////////////////////
	function load( $lpData, &$hdrLen )
	{
		$hdrLen = 0;

		$this->m_nLeft = $this->w2i( substr( $lpData, 0, 2 ) );
		$this->m_nTop = $this->w2i( substr( $lpData, 2, 2 ) );
		$this->m_nWidth = $this->w2i( substr( $lpData, 4, 2 ) );
		$this->m_nHeight = $this->w2i( substr( $lpData, 6, 2 ) );

		if ( !$this->m_nWidth || !$this->m_nHeight ) {
			return false;
		}

		$b = ord( $lpData{8} );
		$this->m_bLocalClr = ( $b &0x80 ) ? true : false;
		$this->m_bInterlace = ( $b &0x40 ) ? true : false;
		$this->m_bSorted = ( $b &0x20 ) ? true : false;
		$this->m_nTableSize = 2 << ( $b &0x07 );
		$hdrLen = 9;

		if ( $this->m_bLocalClr ) {
			$this->m_colorTable = new CGIFCOLORTABLE();
			if ( !$this->m_colorTable->load( substr( $lpData, $hdrLen ), $this->m_nTableSize ) ) {
				return false;
			}
			$hdrLen += 3 * $this->m_nTableSize;
		}

		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function w2i( $str )
	{
		return ord( substr( $str, 0, 1 ) ) + ( ord( substr( $str, 1, 1 ) ) << 8 );
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIFIMAGE {
	var $m_disp;
	var $m_bUser;
	var $m_bTrans;
	var $m_nDelay;
	var $m_nTrans;
	var $m_lpComm;
	var $m_gih;
	var $m_data;
	var $m_lzw;
	// /////////////////////////////////////////////////////////////////////////
	function CGIFIMAGE()
	{
		unSet( $this->m_disp );
		unSet( $this->m_bUser );
		unSet( $this->m_bTrans );
		unSet( $this->m_nDelay );
		unSet( $this->m_nTrans );
		unSet( $this->m_lpComm );
		unSet( $this->m_data );
		$this->m_gih = new CGIFIMAGEHEADER();
		$this->m_lzw = new CGIFLZW();
	}
	// /////////////////////////////////////////////////////////////////////////
	function load( $data, &$datLen )
	{
		$datLen = 0;

		while ( true ) {
			$b = ord( $data{0} );
			$data = substr( $data, 1 );
			$datLen++;

			switch ( $b ) {
				case 0x21: // Extension
					if ( !$this->skipExt( $data, $len = 0 ) ) {
						return false;
					}
					$datLen += $len;
					break;

				case 0x2C: // Image
					// LOAD HEADER & COLOR TABLE
					if ( !$this->m_gih->load( $data, $len = 0 ) ) {
						return false;
					}
					$data = substr( $data, $len );
					$datLen += $len;
					// ALLOC BUFFER
					if ( !( $this->m_data = $this->m_lzw->deCompress( $data, $len = 0 ) ) ) {
						return false;
					}
					$data = substr( $data, $len );
					$datLen += $len;

					if ( $this->m_gih->m_bInterlace ) {
						$this->deInterlace();
					}
					return true;

				case 0x3B: // EOF
				default:
					return false;
			}
		}
		return false;
	}
	// /////////////////////////////////////////////////////////////////////////
	function skipExt( &$data, &$extLen )
	{
		$extLen = 0;

		$b = ord( $data{0} );
		$data = substr( $data, 1 );
		$extLen++;

		switch ( $b ) {
			case 0xF9: // Graphic Control
				$b = ord( $data{1} );
				$this->m_disp = ( $b &0x1C ) >> 2;
				$this->m_bUser = ( $b &0x02 ) ? true : false;
				$this->m_bTrans = ( $b &0x01 ) ? true : false;
				$this->m_nDelay = $this->w2i( substr( $data, 2, 2 ) );
				$this->m_nTrans = ord( $data{4} );
				break;

			case 0xFE: // Comment
				$this->m_lpComm = substr( $data, 1, ord( $data{0} ) );
				break;

			case 0x01: // Plain text
				break;

			case 0xFF: // Application
				break;
		}
		// SKIP DEFAULT AS DEFS MAY CHANGE
		$b = ord( $data{0} );
		$data = substr( $data, 1 );
		$extLen++;
		while ( $b > 0 ) {
			$data = substr( $data, $b );
			$extLen += $b;
			$b = ord( $data{0} );
			$data = substr( $data, 1 );
			$extLen++;
		}
		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function w2i( $str )
	{
		return ord( substr( $str, 0, 1 ) ) + ( ord( substr( $str, 1, 1 ) ) << 8 );
	}
	// /////////////////////////////////////////////////////////////////////////
	function deInterlace()
	{
		$data = $this->m_data;

		for( $i = 0; $i < 4; $i++ ) {
			switch ( $i ) {
				case 0:
					$s = 8;
					$y = 0;
					break;

				case 1:
					$s = 8;
					$y = 4;
					break;

				case 2:
					$s = 4;
					$y = 2;
					break;

				case 3:
					$s = 2;
					$y = 1;
					break;
			}

			for( ; $y < $this->m_gih->m_nHeight; $y += $s ) {
				$lne = substr( $this->m_data, 0, $this->m_gih->m_nWidth );
				$this->m_data = substr( $this->m_data, $this->m_gih->m_nWidth );

				$data =
				substr( $data, 0, $y * $this->m_gih->m_nWidth ) . $lne .
				substr( $data, ( $y + 1 ) * $this->m_gih->m_nWidth );
			}
		}

		$this->m_data = $data;
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////
class CGIF {
	var $m_gfh;
	var $m_lpData;
	var $m_img;
	var $m_bLoaded;
	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTOR
	function CGIF()
	{
		$this->m_gfh = new CGIFFILEHEADER();
		$this->m_img = new CGIFIMAGE();
		$this->m_lpData = "";
		$this->m_bLoaded = false;
	}
	// /////////////////////////////////////////////////////////////////////////
	function loadFile( $lpszFileName, $iIndex )
	{
		if ( $iIndex < 0 ) {
			return false;
		}
		// READ FILE
		if ( !( $fh = @fOpen( $lpszFileName, "rb" ) ) ) {
			return false;
		}
		// EDITEI - in order to read remote files (HTTP(s) and FTP protocols)
		if ( strpos( $lpszFileName, "http" ) !== false or strpos( $lpszFileName, "ftp" ) !== false ) {
			$contents = '';
			while ( !feof( $fh ) ) $contents .= @fread( $fh, 8192 );
		} else {
			$contents = @fread( $fh, @filesize( $lpszFileName ) );
		}
		$this->m_lpData = $contents;
		// $this->m_lpData = @fRead ($fh, @fileSize ($lpszFileName));
		fClose( $fh );
		// GET FILE HEADER
		if ( !$this->m_gfh->load( $this->m_lpData, $len = 0 ) ) {
			return false;
		}
		$this->m_lpData = substr( $this->m_lpData, $len );

		do {
			if ( !$this->m_img->load( $this->m_lpData, $imgLen = 0 ) ) {
				return false;
			}
			$this->m_lpData = substr( $this->m_lpData, $imgLen );
		} while ( $iIndex-- > 0 );

		$this->m_bLoaded = true;
		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function getSize( $lpszFileName, &$width, &$height )
	{
		if ( !( $fh = @fOpen( $lpszFileName, "rb" ) ) ) {
			return false;
		}
		$data = @fRead( $fh, @fileSize( $lpszFileName ) );
		@fClose( $fh );

		$gfh = new CGIFFILEHEADER();
		if ( !$gfh->load( $data, $len = 0 ) ) {
			return false;
		}

		$width = $gfh->m_nWidth;
		$height = $gfh->m_nHeight;
		return true;
	}
	// /////////////////////////////////////////////////////////////////////////
	function getBmp( $bgColor )
	{
		$out = "";

		if ( !$this->m_bLoaded ) {
			return false;
		}
		// PREPARE COLOR TABLE (RGBQUADs)
		if ( $this->m_img->m_gih->m_bLocalClr ) {
			$nColors = $this->m_img->m_gih->m_nTableSize;
			$rgbq = $this->m_img->m_gih->m_colorTable->toRGBQuad();
			if ( $bgColor != -1 ) {
				$bgColor = $this->m_img->m_gih->m_colorTable->colorIndex( $bgColor );
			}
		} else if ( $this->m_gfh->m_bGlobalClr ) {
			$nColors = $this->m_gfh->m_nTableSize;
			$rgbq = $this->m_gfh->m_colorTable->toRGBQuad();
			if ( $bgColor != -1 ) {
				$bgColor = $this->m_gfh->m_colorTable->colorIndex( $bgColor );
			}
		} else {
			$nColors = 0;
			$bgColor = -1;
		}
		// PREPARE BITMAP BITS
		$data = $this->m_img->m_data;
		$nPxl = ( $this->m_gfh->m_nHeight - 1 ) * $this->m_gfh->m_nWidth;
		$bmp = "";
		$nPad = ( $this->m_gfh->m_nWidth % 4 ) ? 4 - ( $this->m_gfh->m_nWidth % 4 ) : 0;
		for( $y = 0; $y < $this->m_gfh->m_nHeight; $y++ ) {
			for( $x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++ ) {
				if (
					( $x >= $this->m_img->m_gih->m_nLeft ) &&
						( $y >= $this->m_img->m_gih->m_nTop ) &&
						( $x < ( $this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth ) ) &&
						( $y < ( $this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight ) ) ) {
					// PART OF IMAGE
					if ( $this->m_img->m_bTrans && ( ord( $data{$nPxl} ) == $this->m_img->m_nTrans ) ) {
						// TRANSPARENT -> BACKGROUND
						if ( $bgColor == -1 ) {
							$bmp .= chr( $this->m_gfh->m_nBgColor );
						} else {
							$bmp .= chr( $bgColor );
						}
					} else {
						$bmp .= $data{$nPxl};
					}
				} else {
					// BACKGROUND
					if ( $bgColor == -1 ) {
						$bmp .= chr( $this->m_gfh->m_nBgColor );
					} else {
						$bmp .= chr( $bgColor );
					}
				}
			}
			$nPxl -= $this->m_gfh->m_nWidth << 1;
			// ADD PADDING
			for( $x = 0; $x < $nPad; $x++ ) {
				$bmp .= "\x00";
			}
		}
		// BITMAPFILEHEADER
		$out .= "BM";
		$out .= $this->dword( 14 + 40 + ( $nColors << 2 ) + strlen( $bmp ) );
		$out .= "\x00\x00";
		$out .= "\x00\x00";
		$out .= $this->dword( 14 + 40 + ( $nColors << 2 ) );
		// BITMAPINFOHEADER
		$out .= $this->dword( 40 );
		$out .= $this->dword( $this->m_gfh->m_nWidth );
		$out .= $this->dword( $this->m_gfh->m_nHeight );
		$out .= "\x01\x00";
		$out .= "\x08\x00";
		$out .= "\x00\x00\x00\x00";
		$out .= "\x00\x00\x00\x00";
		$out .= "\x12\x0B\x00\x00";
		$out .= "\x12\x0B\x00\x00";
		$out .= $this->dword( $nColors % 256 );
		$out .= "\x00\x00\x00\x00";
		// COLOR TABLE
		if ( $nColors > 0 ) {
			$out .= $rgbq;
		}
		// DATA
		$out .= $bmp;

		return $out;
	}
	// /////////////////////////////////////////////////////////////////////////
	function getPng( $bgColor )
	{
		$out = "";

		if ( !$this->m_bLoaded ) {
			return false;
		}
		// PREPARE COLOR TABLE (RGBQUADs)
		if ( $this->m_img->m_gih->m_bLocalClr ) {
			$nColors = $this->m_img->m_gih->m_nTableSize;
			$pal = $this->m_img->m_gih->m_colorTable->toString();
			if ( $bgColor != -1 ) {
				$bgColor = $this->m_img->m_gih->m_colorTable->colorIndex( $bgColor );
			}
		} else if ( $this->m_gfh->m_bGlobalClr ) {
			$nColors = $this->m_gfh->m_nTableSize;
			$pal = $this->m_gfh->m_colorTable->toString();
			if ( $bgColor != -1 ) {
				$bgColor = $this->m_gfh->m_colorTable->colorIndex( $bgColor );
			}
		} else {
			$nColors = 0;
			$bgColor = -1;
		}
		// PREPARE BITMAP BITS
		$data = $this->m_img->m_data;
		$nPxl = 0;
		$bmp = "";
		for( $y = 0; $y < $this->m_gfh->m_nHeight; $y++ ) {
			$bmp .= "\x00";
			for( $x = 0; $x < $this->m_gfh->m_nWidth; $x++, $nPxl++ ) {
				if (
					( $x >= $this->m_img->m_gih->m_nLeft ) &&
						( $y >= $this->m_img->m_gih->m_nTop ) &&
						( $x < ( $this->m_img->m_gih->m_nLeft + $this->m_img->m_gih->m_nWidth ) ) &&
						( $y < ( $this->m_img->m_gih->m_nTop + $this->m_img->m_gih->m_nHeight ) ) ) {
					// PART OF IMAGE
					$bmp .= $data{$nPxl};
				} else {
					// BACKGROUND
					if ( $bgColor == -1 ) {
						$bmp .= chr( $this->m_gfh->m_nBgColor );
					} else {
						$bmp .= chr( $bgColor );
					}
				}
			}
		}
		$bmp = gzcompress( $bmp, 9 );
		// /////////////////////////////////////////////////////////////////////
		// SIGNATURE
		$out .= "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
		// /////////////////////////////////////////////////////////////////////
		// HEADER
		$out .= "\x00\x00\x00\x0D";
		$tmp = "IHDR";
		$tmp .= $this->ndword( $this->m_gfh->m_nWidth );
		$tmp .= $this->ndword( $this->m_gfh->m_nHeight );
		$tmp .= "\x08\x03\x00\x00\x00";
		$out .= $tmp;
		$out .= $this->ndword( crc32( $tmp ) );
		// /////////////////////////////////////////////////////////////////////
		// PALETTE
		if ( $nColors > 0 ) {
			$out .= $this->ndword( $nColors * 3 );
			$tmp = "PLTE";
			$tmp .= $pal;
			$out .= $tmp;
			$out .= $this->ndword( crc32( $tmp ) );
		}
		// /////////////////////////////////////////////////////////////////////
		// TRANSPARENCY
		if ( $this->m_img->m_bTrans && ( $nColors > 0 ) ) {
			$out .= $this->ndword( $nColors );
			$tmp = "tRNS";
			for( $i = 0; $i < $nColors; $i++ ) {
				$tmp .= ( $i == $this->m_img->m_nTrans ) ? "\x00" : "\xFF";
			}
			$out .= $tmp;
			$out .= $this->ndword( crc32( $tmp ) );
		}
		// /////////////////////////////////////////////////////////////////////
		// DATA BITS
		$out .= $this->ndword( strlen( $bmp ) );
		$tmp = "IDAT";
		$tmp .= $bmp;
		$out .= $tmp;
		$out .= $this->ndword( crc32( $tmp ) );
		// /////////////////////////////////////////////////////////////////////
		// END OF FILE
		$out .= "\x00\x00\x00\x00IEND\xAE\x42\x60\x82";

		return $out;
	}
	// /////////////////////////////////////////////////////////////////////////
	function dword( $val )
	{
		$val = intval( $val );
		return chr( $val &0xFF ) . chr( ( $val &0xFF00 ) >> 8 ) . chr( ( $val &0xFF0000 ) >> 16 ) . chr( ( $val &0xFF000000 ) >> 24 );
	}
	// /////////////////////////////////////////////////////////////////////////
	function ndword( $val )
	{
		$val = intval( $val );
		return chr( ( $val &0xFF000000 ) >> 24 ) . chr( ( $val &0xFF0000 ) >> 16 ) . chr( ( $val &0xFF00 ) >> 8 ) . chr( $val &0xFF );
	}
	// /////////////////////////////////////////////////////////////////////////
	function width()
	{
		return $this->m_gfh->m_nWidth;
	}
	// /////////////////////////////////////////////////////////////////////////
	function height()
	{
		return $this->m_gfh->m_nHeight;
	}
	// /////////////////////////////////////////////////////////////////////////
	function comment()
	{
		return $this->m_img->m_lpComm;
	}
	// /////////////////////////////////////////////////////////////////////////
	function loaded()
	{
		return $this->m_bLoaded;
	}
}
// /////////////////////////////////////////////////////////////////////////////////////////////////

?>